const Sequelize = require("sequelize");
const uuid = require("node-uuid");
const date = require("../utils/date");
let config = require("./config");

if (!process.env.NODE_ENV || !config[process.env.NODE_ENV]) {
    console.error("cannot find database config " + process.env.NODE_ENV);
    process.exit(1);
} else {
    config = Object.assign(config, {
        dbname: "seq",
        dialect: "mysql",
        timestamps: false,
        freezeTableName: true,
        pool: {
            max: 5,
            min: 0,
            idle: 10000
        }
    });
}

let sequelize = new Sequelize(config.dbname, config.username, config.password, {
    host: config.host,
    port: config.port,
    dialect: config.dialect,
    pool: config.pool
});

const ID_TYPE = Sequelize.STRING(50);

function generateId() {
    return uuid.v4();
}

function defineModel(name, attributes) {
    var attrs = {};
    for (let key in attributes) {
        let value = attributes[key];
        if (typeof value === "object" && value["type"]) {
            value.allowNull = value.allowNull || false;
            attrs[key] = value;
        } else {
            attrs[key] = {
                type: value,
                allowNull: false
            };
        }
    }
    attrs.id = {
        type: ID_TYPE,
        primaryKey: true
    };
    attrs.createTime = {
        type: Sequelize.TIME,
        field: "create_time",
        allowNull: false
    };
    attrs.updatedTime = {
        type: Sequelize.TIME,
        field: "update_time",
        allowNull: false
    };
    attrs.isDelete = {
        type: Sequelize.INTEGER(2),
        field: "is_delete",
        allowNull: false,
        defaultValue: 0
    };
    return sequelize.define(name, attrs, {
        tableName: name,
        hooks: {
            beforeValidate: function(obj) {
                if (obj.isNewRecord) {
                    if (!obj.id) {
                        obj.id = generateId();
                    }
                    obj.createdTime = date.getDateTime();
                    obj.updatedTime = date.getDateTime();
                } else {
                    obj.updatedTime = date.getDateTime();
                }
            }
        }
    });
}

const TYPES = [
    "STRING",
    "INTEGER",
    "BIGINT",
    "TEXT",
    "DOUBLE",
    "DATEONLY",
    "BOOLEAN"
];

var exp = {
    defineModel: defineModel,
    sync: () => {
        // only allow create ddl in non-production environment:
        if (process.env.NODE_ENV !== "production") {
            sequelize.sync({ force: true });
        } else {
            throw new Error(
                "Cannot sync() when NODE_ENV is set to 'production'."
            );
        }
    }
};

for (let type of TYPES) {
    exp[type] = Sequelize[type];
}

exp.ID = ID_TYPE;
exp.generateId = generateId;

module.exports = exp;
